<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ESP32平衡车参数调节器</title>
    <style>
        /* 全局盒模型设置 */
        * {
            box-sizing: border-box;
        }
        
        body { font-family: sans-serif; padding: 20px; background: #f0f0f0; }
        h1 { margin-top: 10px; text-align: center; }
        #status { margin-bottom: 20px; text-align: center; }
        /* 参数容器样式 */
        #params {
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
            align-items: stretch; /* 确保所有子元素高度一致 */
            gap: 20px;
            margin: 0 auto;
            max-width: 100%;
            padding: 0 10px; /* 添加一些内边距 */
        }
        
        /* 参数分组样式 */
        .param-group {
            background: white;
            padding: 15px;
            border-radius: 8px;
            margin-bottom: 20px;
            box-shadow: 0 0 8px rgba(0,0,0,0.1);
            min-width: 330px;
            max-width: 330px; /* 限制最大宽度 */
            flex: 1;
            transition: box-shadow 0.3s ease;
        }
        
        .group-btn {
  flex: 1;
  margin: 0 4px;
  padding: 6px 0;
  background: #1976d2;
  color: #fff;
  border: none;
  border-radius: 4px;
  font-size: 15px;
  cursor: pointer;
  transition: background 0.2s;
}
.group-btn:hover {
  background: #1565c0;
}

/* 响应式布局 */
@media (max-width: 768px) {
            .param-group {
                min-width: 100%;
                max-width: 100%;
                margin: 0 0 20px 0;
            }
            
            #params {
                flex-direction: column;
                align-items: center;
            }
        }
        
        .param-group-title {
            font-size: 22px;
            font-weight: bold;
            margin-bottom: 15px;
            text-align: center;
            color: #007BFF;
        }
        
        .param {
            background: #eef0f4;
            padding: 10px;
            border-radius: 8px;
            margin-bottom: 15px;
            box-shadow: 0 0 5px rgba(0,0,0,0.05);
            width: 100%;
            overflow: hidden; /* 防止内容溢出 */
        }
        input[type=range] { 
            width: 100%;
        }
        .label-row { display: flex; justify-content: space-between; }

        #status {margin-bottom: 20px}

        #resetBtn {
            background: white;
            padding: 12px 20px;
            border-radius: 8px;
            margin: 20px auto;
            border: 1px solid #007BFF;
            cursor: pointer;
            display: block;
            font-size: 16px;
            transition: all 0.3s ease;
        }
        
    </style>
</head>
<body>
<h1>Esp32 Arduino 平衡+遥控+巡线 智能小车</h1>
<div id="status">🔄 正在连接...</div>

<div id="params"></div>

<script>
    const esp32Location = "192.168.2.192:82"
    const params = [
        // 小车属性
        { name: "angleOffset", min: -12, max: 12, step: 0.1, defaultValue: -7, displayName: "角度修正" },
        { name: "lPwmOffset", min: 0, max: 60, step: 1, defaultValue: 26, displayName: "左电机修正" },
        { name: "rPwmOffset", min: 0, max: 60, step: 1, defaultValue: 26, displayName: "右电机修正" },

        // 直立 PID 参数
        { name: "kp", min: 0, max: 16, step: 0.1, defaultValue: 9.0, displayName: "直立Kp" },
        { name: "ki", min: 0, max: 1, step: 0.01, defaultValue: 0.12, displayName: "直立Ki" },
        { name: "kd", min: 0, max: 1, step: 0.01, defaultValue: 0.16, displayName: "直立Kd" },
        { name: "turnKp", min: 0, max: 0.2, step: 0.01, defaultValue: 0.1, displayName: "转弯Kp" },
        
        // 遥控
        { name: "targetAngle", min: -5, max: 5, step: 0.1, defaultValue: 0, displayName: "前进或后退角度" },
        { name: "turnSpeed", min: -1200, max: 1200, step: 20, defaultValue: 0, displayName: "旋转速度" },

        // 巡线
        { name: "useLineFollower", min: 0, max: 1, step: 1, defaultValue: 0, displayName: "使用巡线" },
        { name: "lineTurnSpeed1", min: 0, max: 1200, step: 20, defaultValue: 380, displayName: "巡线旋转速度1" },
        { name: "lineTurnSpeed2", min: 0, max: 1200, step: 20, defaultValue: 600, displayName: "巡线旋转速度2" },
        { name: "lineAngle", min: 0, max: 5, step: 0.1, defaultValue: 3, displayName: "巡线前进角度" }
    ];

    const container = document.getElementById("params");
    const controls = {};
    
    // 创建四个参数分组
    const baseGroup = document.createElement("div");
    baseGroup.className = "param-group";
    baseGroup.innerHTML = '<div class="param-group-title">小车属性</div>';

    const pidGroup = document.createElement("div");
    pidGroup.className = "param-group";
    pidGroup.innerHTML = '<div class="param-group-title">PID调试</div>';
    
    const manualGroup = document.createElement("div");
    manualGroup.className = "param-group";
    manualGroup.innerHTML = '<div class="param-group-title">手动遥控</div>';
    
    const lineGroup = document.createElement("div");
    lineGroup.className = "param-group";
    lineGroup.innerHTML = '<div class="param-group-title">自动巡线</div>';
    
    // 为每个分组添加操作按钮
    function createGroupButtons(paramNames) {
        let msg = '';

        const btnContainer = document.createElement('div');
        btnContainer.style.display = 'flex';
        btnContainer.style.justifyContent = 'space-between';
        btnContainer.style.marginTop = '10px';
        btnContainer.style.marginBottom = '10px';

        const resetBtn = document.createElement('button');
        resetBtn.textContent = '恢复默认';
        resetBtn.className = 'group-btn';
        resetBtn.onclick = function() {
            paramNames.forEach(name => {
                const p = params.find(item => item.name === name);
                if (p) {
                    controls[name].value = p.defaultValue;
                    document.getElementById(name + '_val').innerText = p.defaultValue;
                    msg = `${name}:${p.defaultValue}`
                    console.log(msg);
                    if (ws.readyState === WebSocket.OPEN) {
                        ws.send(msg);
                    }
                }
            });
        };

        const zeroBtn = document.createElement('button');
        zeroBtn.textContent = '全部置0';
        zeroBtn.className = 'group-btn';
        zeroBtn.onclick = function() {
            paramNames.forEach(name => {
                controls[name].value = 0;
                document.getElementById(name + '_val').innerText = 0;
                msg = `${name}:0`;
                console.log(msg)
                if (ws.readyState === WebSocket.OPEN) {
                    ws.send(msg);
                }
            });
        };

        btnContainer.appendChild(resetBtn);
        btnContainer.appendChild(zeroBtn);
        return btnContainer;
    }

    // 参数分类
    const baseParams = ["angleOffset","lPwmOffset","rPwmOffset"];
    const pidParams = ["kp", "ki", "kd", "turnKp"];
    const manualParams = ["targetAngle", "turnSpeed"];
    const lineParams = ["useLineFollower", "lineTurnSpeed1", "lineTurnSpeed2", "lineAngle"];

    // 将分组添加到容器
    container.appendChild(baseGroup);
    baseGroup.appendChild(createGroupButtons(baseParams));
    container.appendChild(pidGroup);
    pidGroup.appendChild(createGroupButtons(pidParams));
    container.appendChild(manualGroup);
    manualGroup.appendChild(createGroupButtons(manualParams));
    container.appendChild(lineGroup);
    lineGroup.appendChild(createGroupButtons(lineParams));
    
    // 设置初始高亮状态（默认手动模式）
    const defaultBoxStyle = "0 0 8px rgba(0,0,0,0.1)";
    baseGroup.style.boxShadow = defaultBoxStyle;
    manualGroup.style.boxShadow = defaultBoxStyle;
    pidGroup.style.boxShadow = defaultBoxStyle;
    lineGroup.style.boxShadow = defaultBoxStyle;

    // 创建参数控件
    params.forEach(p => {

        let msg = '';

        const div = document.createElement("div");
        div.className = "param";

        div.innerHTML = `
        <div class="label-row">
          <label for="${p.name}">${p.name} (${p.displayName})</label>
          <span id="${p.name}_val">${p.defaultValue}</span>
        </div>
        <input type="range" id="${p.name}" min="${p.min}" max="${p.max}" step="${p.step}" value="${p.defaultValue}">
      `;

        // 根据参数类型添加到对应分组
        if (baseParams.includes(p.name)) {
            baseGroup.appendChild(div);
        } else if (pidParams.includes(p.name)) {
            pidGroup.appendChild(div);
        } else if (manualParams.includes(p.name)) {
            manualGroup.appendChild(div);
        } else if (lineParams.includes(p.name)) {
            lineGroup.appendChild(div);
        }
        
        controls[p.name] = div.querySelector("input");

        controls[p.name].addEventListener("input", () => {
            const value = controls[p.name].value;
            document.getElementById(p.name + "_val").innerText = value;
            msg = `${p.name}:${value}`;
            console.log(msg)
            if (ws.readyState === WebSocket.OPEN) {
                ws.send(msg);
            }
        });
    });

    const ws = new WebSocket(`ws://${esp32Location}`);
    ws.onopen = () => {
        document.getElementById("status").textContent = "✅ 已连接";
        console.log("已连接")
        // 连接成功时的处理
    };
    
    ws.onclose = () => {
        document.getElementById("status").textContent = "❌ 已断开";
        console.log("已断开")
        // 连接断开时的处理
    };
    
</script>
</body>
</html>
